package com.luli.Utils;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;

public class CryptSDK {
    private static final Logger logger = LoggerFactory.getLogger(CryptSDK.class);
    private static final String LINUX_DEFAULT_ETH_NAME = "eth0";
    private static String strInfoPath = "/home/migu/business/encr/";
    private static String strClassPath;
    private static String strIP = getServerIp();

    public static void resetConf(String infoPath, String creditFileName, String ip) {
        if (StringUtils.isNotBlank(infoPath)) {
            strInfoPath = infoPath;
        }
        if (StringUtils.isNotBlank(creditFileName)) {
            strClassPath = strInfoPath + creditFileName;
        } else {
            // 如果未配置，则在info路径下匹配文件
            String jdkbit = System.getProperty("sun.arch.data.model");
            Properties prop = System.getProperties();
            String os = prop.getProperty("os.name");
            System.out.println(os);
            if (!os.startsWith("win") && !os.startsWith("Win")) {
                if (jdkbit.equals("32")) {
                    strClassPath = strInfoPath + "/Linux/32/Native.cws_cebsdk.so";
                } else if (jdkbit.equals("64")) {
                    strClassPath = strInfoPath + "/Linux/64/Native.cws_cebsdk.so";
                }
            } else if (jdkbit.equals("32")) {
                strClassPath = strInfoPath + "/Windows/32/SDK_JNI.dll";
            } else if (jdkbit.equals("64")) {
                strClassPath = strInfoPath + "/Windows/64/SDK_JNI_X64.dll";
            }
        }

        if (StringUtils.isNotEmpty(ip)) {
            strIP = ip;
        }
        try {
            logger.info("==================strIP:{}", strIP);
            logger.info("===============strClassPath:{}", strClassPath);
            logger.info("===============strInfoPath:{}", strInfoPath);
            // 防止重复加载同一个native library,导致UnsatisfiedLinkError，
            // 尝试先复制一个新的版本，然后删除临时文件
            File f = new File(strClassPath);
            String extFile = f.getName().substring(f.getName().lastIndexOf("."));
            String fileNamePath = f.getAbsolutePath().substring(0, f.getAbsolutePath().lastIndexOf("."));
            String descFilePath = fileNamePath + DateFormatUtils.format(new Date(), "HHmmss") + extFile;
            File destFile = new File(descFilePath);
            FileUtils.copyFile(f, destFile);
            System.load(descFilePath);
            logger.info("===============strClassPath temp path:{}", descFilePath);
            //加载后删除文件
            FileUtils.deleteQuietly(destFile);
        } catch (Exception e) {
            logger.error("loder report crypt config file failed. {}", e);
        }
    }

    //  public static void main(String[] str) {}

    public native int Init(String paramString);

    public native int Uninit();

    public native int DecFile(String paramString1, String paramString2);

    public native int EncFile(String paramString1, String paramString2);

    public native byte[] EncStream(
            byte[] paramArrayOfByte, int paramInt1, int paramInt2, int paramInt3);

    public native byte[] DecStream(
            byte[] paramArrayOfByte, int paramInt1, int paramInt2, int paramInt3);

    public void encryptFile(String orignalFile, String encFile) {
        File f = new File(orignalFile);
        String extFile = f.getName().substring(f.getName().lastIndexOf("."));
        String fileNamePath = f.getAbsolutePath().substring(0, f.getAbsolutePath().lastIndexOf("."));
        String copyFilePath = fileNamePath + "-copy" + extFile;
        deleteFiles(f.getParentFile().getAbsolutePath(), 7);
        try {
            FileUtils.copyFile(f, new File(copyFilePath));
            FileUtils.deleteQuietly(f);
        } catch (IOException e) {
            logger.error("IOException occurred.{} ", e);
        }

        logger.info("orignalFile:" + copyFilePath);
        logger.info("encFile:" + encFile);
         CryptSDK sdk = new  CryptSDK();
        logger.info(
                "========SDK.Init:original File:[{}] , /n init param:[{}]",
                copyFilePath,
                "<PARAMATERS><SERVERIP>"
                        + strIP
                        + "</SERVERIP><ENCMAILPATH></ENCMAILPATH><DECMAILPATH></DECMAILPATH><INFOPATH>"
                        + strInfoPath
                        + "</INFOPATH></PARAMATERS>");
        logger.info(
                "SDK.Init:"
                        + copyFilePath
                        + ","
                        + sdk.Init(
                        "<PARAMATERS><SERVERIP>"
                                + strIP
                                + "</SERVERIP><ENCMAILPATH></ENCMAILPATH><DECMAILPATH></DECMAILPATH><INFOPATH>"
                                + strInfoPath
                                + "</INFOPATH></PARAMATERS>"));
        logger.info(
                "=====SDK.EncFile: original File :[{}] , /n enc parame:[file->{},out->{}]",
                new Object[] {
                        copyFilePath,
                        "<PARAMATERS><FILEPATH>" + copyFilePath + "</FILEPATH></PARAMATERS>",
                        "<PARAMATERS><OUTPATH>" + encFile + "</OUTPATH></PARAMATERS>"
                });
        logger.info(
                "SDK.EncFile:"
                        + copyFilePath
                        + ","
                        + sdk.EncFile(
                        "<PARAMATERS><FILEPATH>" + copyFilePath + "</FILEPATH></PARAMATERS>",
                        "<PARAMATERS><OUTPATH>" + encFile + "</OUTPATH></PARAMATERS>"));
        logger.info("SDK.Uninit():" + copyFilePath + "," + sdk.Uninit());
    }

    public void decryptFile(String encFile, String decFile) {
        logger.info("==============encFile:{}" + encFile);
        logger.info("==============decFile:{}" + decFile);
         CryptSDK sdk = new  CryptSDK();
        logger.info(
                "========SDK.Init:original File:[{}],init param:[{}]",
                encFile,
                "<PARAMATERS><SERVERIP>"
                        + strIP
                        + "</SERVERIP><ENCMAILPATH></ENCMAILPATH><DECMAILPATH></DECMAILPATH><INFOPATH>"
                        + strInfoPath
                        + "</INFOPATH></PARAMATERS>");
        logger.info(
                "SDK.Init:"
                        + encFile
                        + ","
                        + sdk.Init(
                        "<PARAMATERS><SERVERIP>"
                                + strIP
                                + "</SERVERIP><ENCMAILPATH></ENCMAILPATH><DECMAILPATH></DECMAILPATH><INFOPATH>"
                                + strInfoPath
                                + "</INFOPATH></PARAMATERS>"));
        logger.info(
                "=====SDK.DecFile: original File :[{}],decrypt parame:[file->{},out->{}]",
                new Object[] {
                        encFile,
                        "<PARAMATERS><FILEPATH>" + encFile + "</FILEPATH></PARAMATERS>",
                        "<PARAMATERS><OUTPATH>" + decFile + "</OUTPATH></PARAMATERS>"
                });
        logger.info(
                "SDK.DecFile:"
                        + encFile
                        + ","
                        + sdk.DecFile(
                        "<PARAMATERS><FILEPATH>" + encFile + "</FILEPATH></PARAMATERS>",
                        "<PARAMATERS><OUTPATH>" + decFile + "</OUTPATH></PARAMATERS>"));
        logger.info("SDK.Uninit():" + encFile + "," + sdk.Uninit());
    }

    /**
     * 删除n天前的文件
     *
     * @param path
     * @param days
     */
    private void deleteFiles(String path, int days) {
        File dir = new File(path);
        if (dir.exists()) {
            File[] lst = dir.listFiles();
            for (File f : lst) {
                if (System.currentTimeMillis() - f.lastModified() > 24 * 60 * 60 * 1000 * days) {
                    f.delete();
                }
            }
        }
    }

    /**
     * 获取服务器地址
     *
     * @return Ip地址
     */
    private static String getServerIp(String... defaultLinuxEthNum) {
        // 获取操作系统类型
        String sysType = System.getProperties().getProperty("os.name");
        String ip;
        // 如果是Windows系统，获取本地IP地址
        if (sysType.startsWith("win") || sysType.startsWith("Win")) {
            String localIP = null;
            try {
                localIP = InetAddress.getLocalHost().getHostAddress();
            } catch (UnknownHostException e) {
                logger.error(e.getMessage(), e);
            }
            if (localIP != null) {
                return localIP;
            }
        } else {
            String ethName;
            if (defaultLinuxEthNum != null && defaultLinuxEthNum.length == 1) {
                ethName = defaultLinuxEthNum[0];
            } else {
                ethName = LINUX_DEFAULT_ETH_NAME;
            }
            logger.info("ethName:{}", ethName);
            ip = getIpByEthNum(ethName); // 兼容Linux
            if (ip != null) {
                return ip;
            }
        }
        return null;
    }

    /**
     * @desc 根据网络接口名获取IP
     * @date wxs 2018-12-12 09:54
     * @param ethNum
     * @return void
     */
    private static String getIpByEthNum(String ethNum) {
        String strIP = null;
        try {
            Enumeration<?> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip;
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
                //        logger.info("(=====netInterface.getName():{}",netInterface.getName());
                if (ethNum.equalsIgnoreCase(netInterface.getName())) {
                    Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                    while (addresses.hasMoreElements()) {
                        ip = addresses.nextElement();
                        if (ip != null && ip instanceof Inet4Address) {
                            strIP = ip.getHostAddress();
                        }
                    }
                }
            }
            //      logger.info("=========local IP:{}" , strIP);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return strIP;
    }
}
